"""
sentry.plugins.bases.notify
~~~~~~~~~~~~~~~~~~~~~~~~~~~

:copyright: (c) 2010-2014 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import absolute_import, print_function

import logging
from six.moves.urllib.parse import (
    urlparse,
    urlencode,
    urlunparse,
    parse_qs,
)

from django import forms

from sentry import digests, ratelimits
from sentry.digests import get_option_key as get_digest_option_key
from sentry.digests.notifications import (
    event_to_record,
    unsplit_key,
)
from sentry.plugins import Notification, Plugin
from sentry.plugins.base.configuration import react_plugin_config
from sentry.models import ProjectOption
from sentry.tasks.digests import deliver_digest


class NotificationConfigurationForm(forms.Form):
    pass


class BaseNotificationUserOptionsForm(forms.Form):
    def __init__(self, plugin, user, *args, **kwargs):
        self.plugin = plugin
        self.user = user
        super(BaseNotificationUserOptionsForm, self).__init__(*args, **kwargs)

    def get_title(self):
        return self.plugin.get_conf_title()

    def get_description(self):
        return ""

    def save(self):
        raise NotImplementedError


class NotificationPlugin(Plugin):
    slug = ''
    description = (
        'Notify project members when a new event is seen for the first time, or when an '
        'already resolved event has changed back to unresolved.'
    )
    # site_conf_form = NotificationConfigurationForm
    project_conf_form = NotificationConfigurationForm

    def configure(self, project, request):
        return react_plugin_config(self, project, request)

    def get_plugin_type(self):
        return 'notification'

    def notify(self, notification):
        event = notification.event
        return self.notify_users(event.group, event)

    def rule_notify(self, event, futures):
        rules = []
        extra = {
            'event_id': event.id,
            'group_id': event.group_id,
            'plugin': self.slug,
        }
        log_event = 'dispatched'
        for future in futures:
            rules.append(future.rule)
            extra['rule_id'] = future.rule.id
            if not future.kwargs:
                continue
            raise NotImplementedError(
                'The default behavior for notification de-duplication does not support args'
            )

        project = event.group.project
        extra['project_id'] = project.id
        if hasattr(self, 'notify_digest') and digests.enabled(project):

            def get_digest_option(key):
                return ProjectOption.objects.get_value(
                    project,
                    get_digest_option_key(self.get_conf_key(), key),
                )

            digest_key = unsplit_key(self, event.group.project)
            extra['digest_key'] = digest_key
            immediate_delivery = digests.add(
                digest_key,
                event_to_record(event, rules),
                increment_delay=get_digest_option('increment_delay'),
                maximum_delay=get_digest_option('maximum_delay'),
            )
            if immediate_delivery:
                deliver_digest.delay(digest_key)
            else:
                log_event = 'digested'

        else:
            notification = Notification(
                event=event,
                rules=rules,
            )
            self.notify(notification)

        self.logger.info('notification.%s' % log_event, extra=extra)

    def notify_users(self, group, event, fail_silently=False):
        raise NotImplementedError

    def notify_about_activity(self, activity):
        pass

    def get_sendable_users(self, project):
        """
        Return a collection of user IDs that are eligible to receive
        notifications for the provided project.
        """
        user_option = '%s:alert' % self.get_conf_key()
        return project.get_notification_recipients(user_option)

    def __is_rate_limited(self, group, event):
        return ratelimits.is_limited(
            project=group.project,
            key=self.get_conf_key(),
            limit=10,
        )

    def is_configured(self, project):
        raise NotImplementedError

    def should_notify(self, group, event):
        project = event.project
        if not self.is_configured(project=project):
            return False

        if group.is_ignored():
            return False

        # If the plugin doesn't support digests or they are not enabled,
        # perform rate limit checks to support backwards compatibility with
        # older plugins.
        if not (hasattr(self, 'notify_digest') and
                digests.enabled(project)) and self.__is_rate_limited(group, event):
            logger = logging.getLogger('sentry.plugins.{0}'.format(self.get_conf_key()))
            logger.info('notification.rate_limited', extra={'project_id': project.id})
            return False

        return True

    def test_configuration(self, project):
        from sentry.utils.samples import create_sample_event
        event = create_sample_event(project, platform='python')
        notification = Notification(event=event)
        return self.notify(notification)

    def get_notification_doc_html(self, **kwargs):
        return ""

    def add_notification_referrer_param(self, url):
        if self.slug:
            parsed_url = urlparse(url)
            query = parse_qs(parsed_url.query)
            query['referrer'] = self.slug

            url_list = list(parsed_url)
            url_list[4] = urlencode(query, doseq=True)
            return urlunparse(url_list)

        return url


# Backwards-compatibility
NotifyConfigurationForm = NotificationConfigurationForm
NotifyPlugin = NotificationPlugin
